#pragma once
#include <Entity.h>
#include <Ship.h>
#include <vector>
#include <Data.h>
#include <SDL/SDL.h>
#include <Resource.h>
#include <Data.h>
#include <so_math.h>
#include <IAnimation.h>
#include <SDL/SDL_ttf.h>
#include <Static.hpp>
#include <cstring>
#include <CollisionManagement.h>
#include <EffectManagement.h>
#include <queue>
#include <Log.h>
#include <Bullet.h>
// #include <Ship.h>
struct PointOrder
{
    Vector2 pos;
    std::stack<Vector2> path;
};
struct HarvestOrder
{
    Entity *harvest;
    Entity *withdraw;
    std::stack<Vector2> path;
};
struct TargetOrder
{
    Entity *target;
    std::stack<Vector2> path;
};
class UnitOrder
{
public:
    UnitOrderType type;
    Entity *sender;
    union OrderData
    {
        TargetOrder targetOrder;
        PointOrder pointOrder;
        HarvestOrder harvestOrder;
        OrderData() {};
        ~OrderData() {};
    } data;
};
class EntityManagement
{
private:
    std::vector<Entity *> entities_list;
    std::unordered_map<Entity *, std::queue<UnitOrder *> *> orders_map;
    Data *data;
    Resource *resource;
    std::vector<Entity *> selected_list;
    std::vector<Entity *> hovers_list;
    std::vector<Bullet *> bullets_list;
    CollisionManagement collisionManagement;
    EffectManagement effectManagement;
    int selectedOwnerID = 0;

public:
    int followRange = 0;
    EntityManagement();
    ~EntityManagement();
    void destroyEntity(Entity *entity);
    void destroyBullet(Bullet *bullet);
    Entity *createEntity(ym::Json *data, Vector2 position, real facing);
    Entity *createShip(ym::Json *data, Vector2 position, int owerPlayerID, real facing);
    Entity *createGold(Vector2 pos);
    Bullet *createBullet(Slot *slot, Entity *owner, Entity *target);
    void createParts(Entity *entity, ym::Json *data);
    IAnimation *createAnimation(ym::Json *data);
    void update(real delta);
    void solveCollision(real delta, int count);
    void updateOrder(real delta);
    void click(int x, int y, int mask);
    void rightClick(int x, int y, int mask);
    void boxSelect(const SDL_Rect *rc, int mask);
    void mouseMotion(int x, int y, int mask);
    Entity *hoverEntity(int x, int y);
    void sendOrder(UnitOrder *unitOrder, bool shift = false);
    const std::vector<Entity *> *getEntities();
    const std::vector<Entity *> *getSelected();
    const std::vector<Entity *> *getHover();
    const std::queue<UnitOrder *> *getUnitOrders(Entity *entity);
    UnitOrder *getTopOrder(Entity *entity);
    const std::list<Collision *> *getCollisions();
    QuadTree *getQuadTree() const;
    void freeQuadTree();
    const std::vector<Effect *> *getEffects();
    const std::vector<Bullet *> *getBullets();

    void unitStop(Entity *entity);

    const std::list<Entity *> findBases(int playerID) const;
    const std::list<Entity *> findResources(ResourceType res) const;
    const std::list<Entity *> findFreeResources(ResourceType res) const;
    Entity *findClosestFreeResource(ResourceType res, Vector2 pos, real range) const;
    Entity *findClosestBase(int playerID, Vector2 pos, real range = 0) const;
    const std::list<CollisionEntity *> *getCollisionEntities() const;
    const Mesh2D *getMesh() const;
    Navmesh *getNavmesh();
    const std::vector<Edge *> *getEdge() const;
};